
#region Imported Namespaces
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
#endregion

namespace PHSRAG.WebControls
{
	#region Class SelectTree
	/// <summary>
	/// </summary>
	/// <remarks>
	/// <p>Derived classes MUST provide the defintion for the javascript function ShouldTreeSelectionCascade which MUST
	/// have the following signature:</p>
	/// <code>function ShouldTreeSelectionCascade(itemType)</code>
	/// <p>This function will be provided with the type of an item that has been selected (via the checkbox), and
	/// should return true to cascade the selection to all children, or false to not cascade.</p>
	/// </remarks>
	[ToolboxData("<{0}:SelectTree runat=server />"), Designer(typeof(SelectTreeDesigner))]
	public abstract class SelectTree : System.Web.UI.WebControls.WebControl, INamingContainer
	{
		#region Constants
		private const string ClientScriptsKey = "clientScripts_3690236F-4D33-4069-99AB-C4C04568BF00";
		private const string DataSourceKey = "dataSource_3690236F-4D33-4069-99AB-C4C04568BF00";
		private const string HiddenFieldPrefix = "hidden";
		#endregion

		#region Instance Variables
		private Hashtable	currentSelection;
		private object	dataSource;
		#endregion

		#region Constructor
		/// <summary>
		/// Initialize the state of this object. The only thing done is to disable view state.
		/// </summary>
		protected SelectTree()
		{
			EnableViewState = false;
		}
		#endregion

		#region Public Properties
		/// <summary>
		/// Get/Set the current selection in the tree. This is expresses as a Hashtable where the key is the displayed
		/// text for a node and the value is whatever the derived classes deem it to be (not used by this class).
		/// </summary>
		public Hashtable CurrentSelection
		{
			get { return currentSelection; }
			set { currentSelection = value; }
		}

		/// <summary>
		/// Get/Set the DataTable which acts as the data source for the tree.
		/// </summary>
		public object DataSource
		{
			get { return dataSource; }
			set { dataSource = value; }
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Create all controls that will be on the SelectTree. Notice that the creation is more than just instantiating
		/// the controls. It also involves in generating the underlying HTML so that the controls shows up per the need.
		/// </summary>
		protected override void CreateChildControls()
		{
			if (IsDesignMode)
				Controls.Add(new LiteralControl(
					"<ul>\n" +
					"	<li><input type=\"checkbox\">&nbsp;Partners\n" +
					"		<ul>\n" +
					"			<li><input type=\"checkbox\">&nbsp;1200 - MGH\n" +
					"				<ul>\n" +
					"					<li><input type=\"checkbox\">&nbsp;30AA - Dermatology\n" +
					"					<li><input type=\"checkbox\">&nbsp;30AA - Medicine\n" +
					"						<ul>\n" +
					"							<li><input type=\"checkbox\">&nbsp;30BA - Rheumatology</li>\n" +
					"							<li><input type=\"checkbox\">&nbsp;30CA - Diabetes</li>\n" +
					"							<li><input type=\"checkbox\">&nbsp;30DA - Cardiology</li>\n" +
					"						</ul>\n" +
					"					</li>\n" +
					"				</ul>\n" +
					"			</li>\n" +
					"			<li><input type=\"checkbox\">&nbsp;BWH\n" +
					"			</li>\n" +
					"		</ul>\n" +
					"	</li>\n" +
					"</ul>\n"));
			else
				CreateControlsAndGenerateControlTree();
		}

		/// <summary>
		/// Ensure that the child controls are created and initialized, and register client-side scripts.
		/// </summary>
		/// <param name="e">Argument associated with the load event</param>
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			EnsureChildControls();
		}

		/// <summary>
		/// Register client-side scripts.
		/// </summary>
		/// <param name="e">Argument associated with the load event</param>
		protected override void OnPreRender(EventArgs e)
		{
			RegisterClientScripts();
			base.OnPreRender(e);
		}
		#endregion

		#region Protected Abstract Methods and Properties
		/// <summary>
		/// Generate the tree (both the data and the associated HTML).
		/// </summary>
		protected abstract void GenerateTree();

		/// <summary>
		/// Get the code for the client script block (if any) that will be registered.
		/// </summary>
		/// <returns>String representation of the script code</returns>
		protected abstract string GetClientScriptBlock();

		/// <summary>
		/// Get the code for the client startup script if any) that will be registered.
		/// </summary>
		/// <returns>String representation of the script code</returns>
		protected abstract string GetStartupScript();

		/// <summary>
		/// Get the list of selections made in the tree. The selection is represented as a string wherein each element
		/// is seprated by a '|' character.
		/// </summary>
		public abstract string Selection { get; }
		#endregion

		#region Private Properties
		/// <summary>
		/// Determine if the control is in design mode. It is if there is not HTTP context.
		/// </summary>
		private static bool IsDesignMode
		{
			get { return HttpContext.Current == null; }
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Create all controls to reflect the actual (and exact) layout.
		/// </summary>
		private void CreateControlsAndGenerateControlTree()
		{
			Controls.Clear();
			GenerateTree();
		}

		/// <summary>
		/// Register client-side script to do the following:
		/// 1. Emit style sheet associated with the tree.
		/// 2. Wire up events generated when a checkbox is clicked upon.
		/// 3. Expand the entire tree.
		/// </summary>
		private void RegisterClientScripts()
		{
            if (!Page.ClientScript.IsClientScriptBlockRegistered(ClientScriptsKey))
			{
                Page.ClientScript.RegisterClientScriptBlock(GetType(), ClientScriptsKey, string.Format(
                    "<script language=\"javascript\" src=\"{0}\"></script>\n" +
                    "<script language=\"javascript\">\ndocument.write(GetSelectTreeStyles('{0}/Images'));\n" +
                    "</script>\n{1}\n", VirtualPathUtility.ToAbsolute("~/Scripts/SelectTree.js"), GetClientScriptBlock()));

                Page.ClientScript.RegisterStartupScript(GetType(), ClientScriptsKey, GetStartupScript());
			}
		}
		#endregion

		#region Internal Methods
		/// <summary>
		/// This method is ONLY invoked by the associated designer to show the control contents at design time.
		/// </summary>
		internal void Design()
		{
			EnsureChildControls();
		}
		#endregion
	}
	#endregion

	#region Class SelectTreeDesigner
	/// <summary>
	/// Designer associated with the SelectTree control.
	/// </summary>
	/// <remarks>
	/// This class cannot be used directly.
	/// </remarks>
	public class SelectTreeDesigner : ControlDesigner
	{
		#region Overrides
		/// <summary>
		/// Force the control to create its child controls for display at design time.
		/// </summary>
		/// <returns>HTML representation of the SelectTree control</returns>
		public override string GetDesignTimeHtml()
		{
			((SelectTree)Component).Design();
			return base.GetDesignTimeHtml();
		}
		#endregion
	}
	#endregion
}

// --- EOF ---
